﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Knight.Common.Security
{
    /// <summary>
    /// DES算法加解密类
    /// </summary>
    public sealed class DES
    {
        internal const string DEFAULT_KEY = "$XH24*";

        /// <summary>
        /// 使用默认密钥加密
        /// </summary>
        public static string DesEncrypt(string strText)
        {
            return DesEncrypt(strText, DEFAULT_KEY);
        }

        /// <summary>
        /// 使用默认解密
        /// </summary>
        public static string DesDecrypt(string strText)
        {
            return DesDecrypt(strText, DEFAULT_KEY);
        }

        /// <summary> 
        /// 加密文本
        /// </summary> 
        public static string DesEncrypt(string strText, string strEncrKey)
        {
            if (string.IsNullOrEmpty(strText))
            {
                return "";
            }

            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

            strEncrKey = strEncrKey.PadRight(8, 'Q');
            var bs = Encoding.UTF8.GetBytes(strEncrKey.Substring(0, 8));
            var byKey = new byte[8];            //解决中文字符导致byte的长度大于8的情况
            Array.Copy(bs, byKey, 8);

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            byte[] inputByteArray = Encoding.UTF8.GetBytes(strText);
            try
            {
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                return System.Convert.ToBase64String(ms.ToArray());
            }
            catch
            {
                throw new ApplicationException("加密失败");
            }
        }

        /// <summary> 
        /// 解密文本
        /// </summary> 
        public static string DesDecrypt(string strText, string sDecrKey)
        {
            if (string.IsNullOrEmpty(strText))
            {
                return "";
            }

            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
            byte[] inputByteArray = new Byte[strText.Length];

            sDecrKey = sDecrKey.PadRight(8, 'Q');
            var bs = Encoding.UTF8.GetBytes(sDecrKey.Substring(0, 8));
            var byKey = new byte[8];            //解决中文字符导致byte的长度大于8的情况
            Array.Copy(bs, byKey, 8);

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            try
            {
                inputByteArray = System.Convert.FromBase64String(strText);
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                Encoding encoding = new UTF8Encoding();
                return encoding.GetString(ms.ToArray());
            }
            catch
            {
                throw new ApplicationException("解密失败");
            }

        }

        /// <summary> 
        /// 加密文件
        /// </summary> 
        /// <param name="m_InFilePath">输入文件名</param> 
        /// <param name="m_OutFilePath">加密输出文件名</param> 
        /// <param name="strEncrKey">密钥</param> 
        public static void DesEncrypt(string m_InFilePath, string m_OutFilePath, string strEncrKey)
        {
            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

            strEncrKey = strEncrKey.PadRight(8, 'Q');
            var bs = Encoding.UTF8.GetBytes(strEncrKey.Substring(0, 8));
            var byKey = new byte[8];            //解决中文字符导致byte的长度大于8的情况
            Array.Copy(bs, byKey, 8);

            FileStream fin = new FileStream(m_InFilePath, FileMode.Open, FileAccess.Read);
            FileStream fout = new FileStream(m_OutFilePath, FileMode.OpenOrCreate, FileAccess.Write);
            fout.SetLength(0);
            //Create variables to help with read and write. 
            byte[] bin = new byte[100]; //This is intermediate storage for the encryption. 
            long rdlen = 0; //This is the total number of bytes written. 
            long totlen = fin.Length; //This is the total length of the input file. 
            int len; //This is the number of bytes to be written at a time. 

            System.Security.Cryptography.DES des = new DESCryptoServiceProvider();
            CryptoStream encStream = new CryptoStream(fout, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write);

            //Read from the input file, then encrypt and write to the output file. 
            while (rdlen < totlen)
            {
                len = fin.Read(bin, 0, 100);
                encStream.Write(bin, 0, len);
                rdlen = rdlen + len;
            }
            encStream.Close();
            fout.Close();
            fin.Close();
        }
        /// <summary>
        /// 加密文件
        /// </summary>
        /// <param name="m_inStream">文件数据流</param>
        /// <param name="m_OutFilePath">加密输出文件名</param>
        /// <param name="strEncrKey">密钥</param>
        public static void DesEncrypt(MemoryStream m_inStream, string m_OutFilePath, string strEncrKey)
        {
            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

            strEncrKey = strEncrKey.PadRight(8, 'Q');
            var bs = Encoding.UTF8.GetBytes(strEncrKey.Substring(0, 8));
            var byKey = new byte[8];            //解决中文字符导致byte的长度大于8的情况
            Array.Copy(bs, byKey, 8);

            //FileStream fin = new FileStream(m_InFilePath, FileMode.Open, FileAccess.Read);
            FileStream fout = new FileStream(m_OutFilePath, FileMode.OpenOrCreate, FileAccess.Write);
            fout.SetLength(0);
            //Create variables to help with read and write. 
            byte[] bin = new byte[100]; //This is intermediate storage for the encryption. 
            long rdlen = 0; //This is the total number of bytes written. 
            long totlen = m_inStream.Length; //This is the total length of the input file. 
            int len; //This is the number of bytes to be written at a time. 

            System.Security.Cryptography.DES des = new DESCryptoServiceProvider();
            CryptoStream encStream = new CryptoStream(fout, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write);

            //Read from the input file, then encrypt and write to the output file. 
            m_inStream.Position = 0;
            while (rdlen < totlen)
            {
                len = m_inStream.Read(bin, 0, 100);
                encStream.Write(bin, 0, len);
                rdlen = rdlen + len;
            }
            encStream.Close();
            fout.Close();
            m_inStream.Close();
        }

        /// <summary> 
        /// 解密文件
        /// </summary> 
        /// <param name="m_InFilePath">密文文件</param> 
        /// <param name="m_OutFilePath">解密输出文件</param> 
        /// <param name="sDecrKey">密钥</param> 
        public static void DesDecrypt(string m_InFilePath, string m_OutFilePath, string sDecrKey)
        {
            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

            sDecrKey = sDecrKey.PadRight(8, 'Q');
            var bs = Encoding.UTF8.GetBytes(sDecrKey.Substring(0, 8));
            var byKey = new byte[8];            //解决中文字符导致byte的长度大于8的情况
            Array.Copy(bs, byKey, 8);

            FileStream fin = new FileStream(m_InFilePath, FileMode.Open, FileAccess.Read);
            FileStream fout = new FileStream(m_OutFilePath, FileMode.OpenOrCreate, FileAccess.Write);
            fout.SetLength(0);
            //Create variables to help with read and write. 
            byte[] bin = new byte[100]; //This is intermediate storage for the encryption. 
            long rdlen = 0; //This is the total number of bytes written. 
            long totlen = fin.Length; //This is the total length of the input file. 
            int len; //This is the number of bytes to be written at a time. 

            System.Security.Cryptography.DES des = new DESCryptoServiceProvider();
            CryptoStream encStream = new CryptoStream(fout, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write);

            //Read from the input file, then encrypt and write to the output file. 
            while (rdlen < totlen)
            {
                len = fin.Read(bin, 0, 100);
                encStream.Write(bin, 0, len);
                rdlen = rdlen + len;
            }
            encStream.Close();
            fout.Close();
            fin.Close();
        }

        /// <summary> 
        /// 解密文件
        /// </summary> 
        /// <param name="m_InFilePath">密文文件</param> 
        /// <param name="m_OutStream">解密输出数据流</param>
        /// <param name="sDecrKey">密钥</param> 
        public static void DesDecrypt(string m_InFilePath, MemoryStream m_OutStream, string sDecrKey)
        {
            byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };

            sDecrKey = sDecrKey.PadRight(8, 'Q');
            var bs = Encoding.UTF8.GetBytes(sDecrKey.Substring(0, 8));
            var byKey = new byte[8];            //解决中文字符导致byte的长度大于8的情况
            Array.Copy(bs, byKey, 8);

            FileStream fin = new FileStream(m_InFilePath, FileMode.Open, FileAccess.Read);
            //FileStream fout = new FileStream(m_OutFilePath, FileMode.OpenOrCreate, FileAccess.Write);
            m_OutStream.SetLength(0);
            //Create variables to help with read and write. 
            byte[] bin = new byte[100]; //This is intermediate storage for the encryption. 
            long rdlen = 0; //This is the total number of bytes written. 
            long totlen = fin.Length; //This is the total length of the input file. 
            int len; //This is the number of bytes to be written at a time. 

            System.Security.Cryptography.DES des = new DESCryptoServiceProvider();
            CryptoStream encStream = new CryptoStream(m_OutStream, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write);

            //Read from the input file, then encrypt and write to the output file. 
            while (rdlen < totlen)
            {
                len = fin.Read(bin, 0, 100);
                encStream.Write(bin, 0, len);
                rdlen = rdlen + len;
            }
            //encStream.Close(); 
            //m_OutStream.Close();
            fin.Close();
        }

    }
}
